package com.webc.framework.bean;

import com.webc.framework.annotation.DeleteMapping;
import com.webc.framework.annotation.GetMapping;
import com.webc.framework.annotation.PostMapping;
import com.webc.framework.annotation.PutMapping;
import com.webc.framework.annotation.RestController;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class MappingContainer {

    private static final Map<String, Object> BEAN_CONTAINER = BeanContainer.getBeanContainer();

    private static final Map<String, RequestHandler> HANDLER_MAPPING = new HashMap<>();

    public static final Class[] MAPPING_ANNOTATION_CLASS = {
            GetMapping.class,
            PostMapping.class,
            PutMapping.class,
            DeleteMapping.class
    };

    private static Map<String, Object> CONTROLLER_BEAN_CONTAINER = new HashMap<>();

    static {
        BEAN_CONTAINER.entrySet().forEach(entry -> {
            Annotation annotation = entry.getValue().getClass().getAnnotation(RestController.class);
            if(annotation != null) {
                CONTROLLER_BEAN_CONTAINER.put(entry.getKey(), entry.getValue());
            }
        });
    }

    public static Map<String, RequestHandler> getRequestHandlerMapping() {
        return HANDLER_MAPPING;
    }

    public static void initHandlerMapping() {
        CONTROLLER_BEAN_CONTAINER.entrySet().forEach(entry -> {
            Object instance = entry.getValue();
            Method[] methods = instance.getClass().getDeclaredMethods();
            Arrays.asList(methods).forEach(method -> {
                handlerMapper(method, instance);
            });
        });
    }

    private static void handlerMapper(Method method, Object instance) {
        for(Class clazz: MAPPING_ANNOTATION_CLASS) {
            Annotation an = method.getAnnotation(clazz);
            if(an != null) {
                String mappingPath = getMappingPath(method, clazz);
                RequestHandler handler = new RequestHandler(method, instance, clazz);
                RequestHandler tmpRequestHandler = HANDLER_MAPPING.get(mappingPath);
                if (tmpRequestHandler != null) {
                    throw new RuntimeException(mappingPath + " already exits");
                }
                HANDLER_MAPPING.put(mappingPath, handler);
            }
        }
    }

    private static String getMappingPath(Method method, Class clazz) {
        String className = clazz.getName().substring(clazz.getName().lastIndexOf(".") + 1, clazz.getName().length());
        switch (className) {
            case "GetMapping":
                return method.getAnnotation(GetMapping.class).path();
            case "PostMapping":
                return method.getAnnotation(PostMapping.class).path();
            case "PutMapping":
                return method.getAnnotation(PutMapping.class).path();
            case "DeleteMapping":
                return method.getAnnotation(PutMapping.class).path();
            default:
                throw new RuntimeException("mapping exception: " + clazz.getName());
        }
    }
}

